package fem2.strategies;

import inf.jlinalg.ArrayVector;
import inf.jlinalg.SolveFailedException;
import fem2.Debugger;
import fem2.Model;
import fem2.element.StructuralElement;
import fem2.jlinalg.Solver;
import fem2.material.TopOptMaterialModel;

public class TopOptStrategy extends NewtonRaphsonStrategy {

	private double objective;
	private TopOptMaterialModel mm;
	private double lambda;

	public TopOptStrategy(Model m, double objective) {
		super(m);
		this.objective = objective;
		mm = (TopOptMaterialModel) ((StructuralElement) m.getElement(0)).getMaterialModel();
		lambda = 1.0 / nt;
	}

	@Override
	public void setNumberOfTimeStep(int nt) {
		this.nt = nt;
		lambda = 1.0 / nt;
	}

	@Override
	public double getNextTimeStep() {
		return lambda;
	}

	@Override
	public double getCurrentTimeStep() {
		return lambda;
	}

	@Override
	public void solve() throws SolveFailedException {

		Solver solver = createSolver();
		solver.setEchoLevel(getEchoLevel());

		Debugger.warn(solver.getClass().getName());

		ArrayVector rhs = new ArrayVector();
		ArrayVector u = new ArrayVector();

		Debugger.watch("Time stepping start");

		started(solver, rhs, u);
		fireStarted();

		int i = 0;
		int cnt = 1;
		while (true) {

			boolean conv = solveOneStep(i, solver, rhs, u);

			if (!conv) {
				Debugger.warn("Analysis stopped at time step " + (i + 1));
				break;
			}

			i++;

			if (mm.getDensityChange() < objective) {
				if (cnt < nt) {
					cnt++;
					lambda += 1.0 / nt;
				} else {
					break;
				}
			}

		}

		finished(solver, rhs, u);
		fireFinished();

		Debugger.watch("Time stepping completed");
	}
}
